package il.technion.ewolf.beehive;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import com.google.inject.Inject;
import com.google.inject.name.Named;
import com.google.inject.name.Names;

/***
 * This class hold statistics for the run of the project
 * @author Ligal ligal2@gmail.com
 * @author Hen senderhen@gmail.com
 */
public class BeehiveStatistics {
	
	private AtomicInteger nrFindValueHits;
	private AtomicInteger nrFindValueMiss;
	private AtomicBoolean replication;
	private AtomicInteger totalCount;
	private int threshold;
	private AtomicInteger nrFindValueHops;
	private AtomicInteger nrObjectsRequests;
	private AtomicInteger nrObjectsInStorage;
	private AtomicInteger maxObjectsInStorage; 
	private AtomicInteger nUpdatesOfStorage; 
	private AtomicInteger nRepMessages;
	private AtomicInteger nToldToDelete;
	private AtomicInteger nNumberToldToDeleteMsg;
	
	@Inject
	public BeehiveStatistics(
			@Named("openkad.testing.nrFindValueHits") AtomicInteger p_nrFindValueHits,
			@Named("openkad.testing.nrFindValueMiss") AtomicInteger p_nrFindValueMiss,
			@Named("openkad.testing.replication") AtomicBoolean p_replication,
			@Named("openkad.testing.totalCount") AtomicInteger p_totalCount,
			@Named("openkad.beehive.valueThreshold") int p_threshold,
			@Named("openkad.testing.nrFindValueHops") AtomicInteger p_nrFindValueHops, 
			@Named("openkad.testing.nrObjectsRequests") AtomicInteger p_nrObjectsRequests, 
			@Named("openkad.testing.nrObjectsInStorage") AtomicInteger p_nrObjectsInStorage, 
			@Named("openkad.testing.maxObjectsInStorage") AtomicInteger p_maxObjectsInStorage, 
			@Named("openkad.testing.nUpdatesOfStorage") AtomicInteger p_nUpdatesOfStorage, 
			@Named("openkad.testing.nRepMessages") AtomicInteger p_nRepMessages, 
			@Named("openkad.testing.nToldToDelete") AtomicInteger p_nToldToDelete, 
			@Named("openkad.testing.nNumberToldToDeleteMsg") AtomicInteger p_nNumberToldToDeleteMsg){
		
		nrFindValueHits = p_nrFindValueHits;
		nrFindValueMiss = p_nrFindValueMiss;
		replication = p_replication;
		totalCount = p_totalCount;
		threshold = p_threshold;
		nrFindValueHops = p_nrFindValueHops;
		nrObjectsRequests = p_nrObjectsRequests;
		nrObjectsInStorage = p_nrObjectsInStorage;
		maxObjectsInStorage = p_maxObjectsInStorage; 
		nUpdatesOfStorage = p_nUpdatesOfStorage; 
		nRepMessages = p_nRepMessages;
		nToldToDelete = p_nToldToDelete;
		nNumberToldToDeleteMsg = p_nNumberToldToDeleteMsg;
	}
	
	public boolean isStoped (int sum){
		return (!replication.get() && (totalCount.get() < threshold));
	}
	
	public void print(BufferedWriter out){
		try {
			if ((double)nrObjectsRequests.get() == 0){
				out.write("Average_lookup_for_value: " + (((double)nrFindValueHops.get()) / (1.0)) + "\r\n");
			}
			else {
				out.write("Average_lookup_for_value: " + (((double)nrFindValueHops.get()) / ((double)nrObjectsRequests.get())) + "\r\n");
			}
			if ((double)nUpdatesOfStorage.get() == 0){
				out.write("Avarage_number_of_objects_in_storage: " + (((double)nrObjectsInStorage.get()) / (1.0)) + "\r\n");
			}
			else {
				out.write("Avarage_number_of_objects_in_storage: " + (((double)nrObjectsInStorage.get()) / ((double)nUpdatesOfStorage.get())) + "\r\n");
			}
			out.write("Max_objects_in_storage: " + maxObjectsInStorage + "\r\n");
			
			out.write("Number_of_replication_message: " + nRepMessages + "\r\n");
			
			if (((double)nRepMessages.get() + (double)nrFindValueHits.get() + (double)nrFindValueMiss.get()) == 0.0)
			{
				out.write("Relative_number_of_replication_message: " + (((double)nRepMessages.get()) / 1.0) + "\r\n");
			}
			else
			{
				out.write("Relative_number_of_replication_message: " + (((double)nRepMessages.get()) / ((double)nRepMessages.get() + (double)nrFindValueHits.get() + (double)nrFindValueMiss.get())) + "\r\n");
			}
			
			if (((double)nNumberToldToDeleteMsg.get()) == 0.0)
			{
				out.write("Avarage_number_of_objects_B_suggests_to_delete: " + (((double)nToldToDelete.get()) / 1.0) + "\r\n");
			}
			else
			{
				out.write("Avarage_number_of_objects_B_suggests_to_delete: " + (((double)nToldToDelete.get()) / ((double)nNumberToldToDeleteMsg.get())) + "\r\n");
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void clear (){
		nrFindValueHits.set(0);
		nrFindValueMiss.set(0);
		totalCount.set(0);
		nrFindValueHops.set(0);
		nrObjectsRequests.set(0);
		maxObjectsInStorage.set(0);  
		nRepMessages.set(0);
		nToldToDelete.set(0);
		nNumberToldToDeleteMsg.set(0);
	}
}
